import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

/**
 * @author wcj
 * @Date 2021/7/26 16:24
 * @Version 1.0
 */
public class ProducerConsumer {

    private static volatile Queue<Integer> queue = new LinkedList<>();
    // 队列的容量
    private static volatile int cap = 10;
    private static final Object obj = new Object();

    /**
     * 生产者消费者模式的基本思路：
     * ①有一个共享缓冲区用于双方从中进行元素的放入和获取，这里使用一个队列来替代
     * 经典的通知者消费者模式的实现：
     * 通知者：
     * 1，首先获取到锁
     * 2，然后判断当前缓冲区是否满了，如果满了就睡眠等待消费者唤醒
     * 3，如果没满，
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        Producer producer = new Producer();
        new Thread(producer).start();
        Thread.sleep(1);
        Consumer consumer = new Consumer();
        new Thread(consumer).start();
    }

    /**
     * 生产者线程
     */
    static class Producer implements Runnable {

        @Override
        public void run() {
            while (true) {
                // 获取锁
                synchronized (obj) {
                    // 判断条件是否满足，即队列是否已经满了
                    if (queue.size() != cap) {
                        // 如果条件满足，即队列没满，生产数据放入队列
                        System.out.println("队列中数据没满，继续生产!当前队列内元素数量" + queue.size());
                        queue.add(new Random(47).nextInt(10));
                        // 并且通知消费者线程进行消费
                        obj.notify();
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        // 如果队列已经满了，睡眠等待消费者消费完毕唤醒
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 消费者线程
     */
    static class Consumer implements Runnable {

        @Override
        public void run() {
            while (true) {
                // 获取锁
                synchronized (obj) {
                    // 判断条件是否满足
                    if (!queue.isEmpty()) {
                        // 消费数据
                        System.out.println("队列中有数据，当前队列内元素数量:+" + queue.size() + "消费当前数据：" + queue.poll());
                        // 唤醒生产者线程继续生产
                        obj.notify();
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        // 条件不满足，继续睡眠
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
